package com.swak.frame.ratelimit.parser;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.core.annotation.AnnotationUtils;

import com.swak.frame.filter.SwakMethodUtils;
import com.swak.frame.filter.annotation.SwakMethod;
import com.swak.frame.interceptor.SwakAnnotationUtils;
import com.swak.frame.ratelimit.RateLimitAnnotationParser;
import com.swak.frame.ratelimit.RateLimitCodeUtil;
import com.swak.frame.ratelimit.annotation.RateLimit;
import com.swak.frame.ratelimit.config.LimitOperation;
import com.swak.frame.system.SystemConfigurable;

public class LimitRaterFilterAnnotationParser implements RateLimitAnnotationParser {

	private static final Set<Class<? extends Annotation>> SWAK_METHOD_ANNOTATIONS = new LinkedHashSet<>(1);
	static {
		SWAK_METHOD_ANNOTATIONS.add(SwakMethod.class);
	}

	private SystemConfigurable systemConfig;

	/**
	 * {@link SwakMethod} not support class,@Target is method
	 */
	@Override
	public Collection<LimitOperation> parseAnnotations(Class<?> type) {
		return Collections.emptyList();
	}

	@Override
	public Collection<LimitOperation> parseAnnotations(Method method,Class<?> targetClass) {
		Collection<? extends Annotation> anns = SwakAnnotationUtils.parseAnnotations(method, SWAK_METHOD_ANNOTATIONS);
		if (CollectionUtils.isNotEmpty(anns)) {
			// 处理 RateLimit和SwakMethod
			final Collection<LimitOperation> operation = new ArrayList<>(1);
			anns.stream().filter(ann -> (ann instanceof SwakMethod))
					.forEach(ann -> operation.add(parseRateLimitAnnotation(method, method.getDeclaringClass(), ann)));
			return operation;
		}
		return Collections.emptyList();
	}

	private LimitOperation parseRateLimitAnnotation(Method method, Class<?> targetClass, Annotation ann) {
		RateLimit rateLimit = null;
		SwakMethod swakMethod = null;
		if (ann instanceof SwakMethod) {
			swakMethod = (SwakMethod) ann;
			if (ArrayUtils.isNotEmpty(swakMethod.rateLimit())) {
				rateLimit = swakMethod.rateLimit()[0];
			} else {
				rateLimit = SwakMethodUtils.getSwakMethodRateLimit((SwakMethod) ann, systemConfig);
			}
		}
		if (rateLimit == null) {
			return null;
		}
		String resource = RateLimitCodeUtil.getlimtResource(rateLimit, method, targetClass);
		return LimitOperation.newLimitOperation(resource, rateLimit, swakMethod.desc());
	}

	@Override
	public boolean isCandidateClass(Class<?> targetClass) {
		return AnnotationUtils.isCandidateClass(targetClass, SWAK_METHOD_ANNOTATIONS);
	}

	public void setSystemConfig(SystemConfigurable systemConfig) {
		this.systemConfig = systemConfig;
	}
}
